package com.jzo2o.orders.manager.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.model.msg.TradeStatusMsg;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.orders.base.enums.OrderPayStatusEnum;
import com.jzo2o.orders.base.enums.OrderStatusChangeEventEnum;
import com.jzo2o.orders.base.enums.OrderStatusEnum;
import com.jzo2o.orders.base.handler.OrderPayedHandler;
import com.jzo2o.orders.base.mapper.OrdersMapper;
import com.jzo2o.orders.base.model.domain.Orders;
import com.jzo2o.orders.base.model.dto.OrderSnapshotDTO;
import com.jzo2o.orders.manager.model.dto.request.OrdersPayReqDTO;
import com.jzo2o.orders.manager.model.dto.response.OrdersPayResDTO;
import com.jzo2o.orders.manager.porperties.TradeProperties;
import com.jzo2o.orders.manager.service.IOrdersCreateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.util.List;

import static com.jzo2o.common.constants.ErrorInfo.Code.TRADE_FAILED;

/**
 * <p>
 * 下单服务类
 * </p>
 *
 * @author itcast
 * @since 2023-07-10
 */
@Slf4j
@Service
public class OrdersCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersCreateService {

    @Resource
    private NativePayApi nativePayApi;
    @Resource
    private TradeProperties properties;
    @Resource
    private TradingApi tradingApi;
    @Resource
    private OrdersCreateServiceImpl impl;
    @Resource
    private OrderPayedHandler orderPayedHandler;

    /**
     * 订单支付
     * @param id 订单id
     * @param ordersPayReqDTO 订单信息
     * @return OrdersPayResDTO
     */
    @Transactional
    @Override
    public OrdersPayResDTO pay(Long id, OrdersPayReqDTO ordersPayReqDTO) {
        Orders orders = baseMapper.selectById(id);
        // 判断订单是否存在
        if(ObjectUtils.isNull(orders)) {
            throw new CommonException("您所支付的订单异常，请联系客服");
        }
        // 判断订单是否支付成功
        if(orders.getPayStatus() ==  OrderPayStatusEnum.PAY_SUCCESS.getStatus()) {
            // 成功就结束返回数据
            OrdersPayResDTO dto = new OrdersPayResDTO();
            dto.setProductOrderNo(orders.getId());
            dto.setTradingChannel(orders.getTradingChannel());
            dto.setPayStatus(orders.getPayStatus());
            return dto;
        } else {
            // 没有支付成功则执行支付逻辑
            NativePayReqDTO dto = payMethods(orders, ordersPayReqDTO);


            // 生成支付二维码
            NativePayResDTO nativePayResDTO
                    = nativePayApi.createDownLineTrading(dto);

            // 更新订单支付信息
            // 使用状态机来实现代码逻辑
            OrderSnapshotDTO bizSnapshot =
                    BeanUtils.toBean(baseMapper.selectById(id), OrderSnapshotDTO.class);
            orderPayedHandler.handler(id.toString(), OrderStatusChangeEventEnum.PAYED, bizSnapshot);
            /*boolean update = lambdaUpdate()
                    .eq(Orders::getId, nativePayResDTO.getProductOrderNo())
                    .set(Orders::getOrdersStatus, OrderStatusEnum.NO_PAY.getStatus())
                    .set(Orders::getPayStatus, OrderPayStatusEnum.NO_PAY.getStatus())
                    .update();
            if(!update) {
                throw new CommonException("更新订单支付号失败，请联系客服");
            }*/

            // 封装最后的返回结果/并返回
            OrdersPayResDTO ordersPayResDTO = new OrdersPayResDTO();
            ordersPayResDTO.setQrCode(nativePayResDTO.getQrCode());
            ordersPayResDTO.setProductOrderNo(dto.getProductOrderNo());
            ordersPayResDTO.setTradingOrderNo(nativePayResDTO.getTradingOrderNo());
            ordersPayResDTO.setTradingChannel(nativePayResDTO.getTradingChannel());
            ordersPayResDTO.setPayStatus(TradingStateEnum.FKZ.getCode());
            return ordersPayResDTO;
        }
    }

    /**
     * 查询订单支付结果
     * @param id 订单id
     * @return OrderPayResDTO
     */
    @Override
    public OrdersPayResDTO payResult(Long id) {
        Orders orders = baseMapper.selectById(id);
        // 判断订单状态是否为未支付
        if(orders.getPayStatus() == OrderPayStatusEnum.NO_PAY.getStatus()) {
            // 调用支付接口查询支付结果
            TradingResDTO dto
                    = tradingApi.findTradResultByTradingOrderNo(orders.getTradingOrderNo());
            // 判断是否支付成功，成功封装数据更新订单信息
            if(dto.getTradingState().getCode() == OrderPayStatusEnum.PAY_SUCCESS.getStatus()) {
                // 封装数据更新订单数据
                TradeStatusMsg tradeStatusMsg = new TradeStatusMsg();
                tradeStatusMsg.setTradingOrderNo(orders.getTradingOrderNo());
                tradeStatusMsg.setProductAppId("jzo2o.orders");
                tradeStatusMsg.setProductOrderNo(orders.getId());
                tradeStatusMsg.setTransactionId(dto.getTransactionId());
                tradeStatusMsg.setTradingChannel(dto.getTradingChannel());
                tradeStatusMsg.setRefundNo(0L);
                tradeStatusMsg.setStatusName(OrderPayStatusEnum.PAY_SUCCESS.getDesc());
                tradeStatusMsg.setStatusCode(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
                impl.updateOrderInfo(tradeStatusMsg);

                // 封装结果/并返回
                OrdersPayResDTO ordersPayResDTO = BeanUtils.toBean(dto, OrdersPayResDTO.class);
                ordersPayResDTO.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
                return ordersPayResDTO;
            }
        }

        OrdersPayResDTO ordersPayResDTO = new OrdersPayResDTO();
        ordersPayResDTO.setPayStatus(orders.getPayStatus());
        ordersPayResDTO.setProductOrderNo(orders.getId());
        ordersPayResDTO.setTradingOrderNo(orders.getTradingOrderNo());
        ordersPayResDTO.setTradingChannel(orders.getTradingChannel());
        return ordersPayResDTO;
    }

    // 支付成功更新订单信息
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderInfo(TradeStatusMsg tradeStatusMsg) {
        //查询订单
        Orders orders = baseMapper.selectById(tradeStatusMsg.getProductOrderNo());
        if (ObjectUtil.isNull(orders)) {
            throw new CommonException(TRADE_FAILED, "订单不存在");
        }
        //校验支付状态如果不是待支付状态则不作处理
        if (ObjectUtil.notEqual(OrderPayStatusEnum.NO_PAY.getStatus(), orders.getPayStatus())) {
            log.info("更新订单支付成功，当前订单:{}支付状态不是待支付状态", orders.getId());
            return;
        }
        //校验订单状态如果不是待支付状态则不作处理
        if (ObjectUtils.notEqual(OrderStatusEnum.NO_PAY.getStatus(),orders.getOrdersStatus())) {
            log.info("更新订单支付成功，当前订单:{}状态不是待支付状态", orders.getId());
        }

        //第三方支付单号校验
        if (ObjectUtil.isEmpty(tradeStatusMsg.getTransactionId())) {
            throw new CommonException("支付成功通知缺少第三方支付单号");
        }
        boolean update = lambdaUpdate()
                .eq(Orders::getId, tradeStatusMsg.getProductOrderNo())
                .set(Orders::getTransactionId, tradeStatusMsg.getTransactionId())
                .set(Orders::getPayTime, LocalDateTime.now())
                .set(Orders::getOrdersStatus, OrderStatusEnum.DISPATCHING.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getTradingChannel, tradeStatusMsg.getTradingChannel())
                .set(Orders::getTradingOrderNo, tradeStatusMsg.getTradingOrderNo())
                .update();
        if(!update) {
            log.info("更新订单:{}支付成功失败", orders.getId());
            throw new CommonException("更新订单"+orders.getId()+"支付成功失败");
        }
    }

    /**
     * 查询超时订单id列表
     * @param count 数量
     * @return 订单id列表
     */
    @Override
    public List<Orders> queryOverTimePayOrdersListByCount(Integer count) {
        List<Orders> orderList = lambdaQuery()
                .eq(Orders::getOrdersStatus, OrderStatusEnum.NO_PAY.getStatus())
                .lt(Orders::getCreateTime, LocalDateTime.now().minusMinutes(15))
                .last("limit " + count + "")
                .list();
        return orderList;
    }

    private NativePayReqDTO payMethods(Orders orders, OrdersPayReqDTO ordersPayReqDTO) {
        // 封装支付请求参数，请求微信支付服务
        NativePayReqDTO dto = new NativePayReqDTO();
        // 商户号
        PayChannelEnum tradingChannel = ordersPayReqDTO.getTradingChannel();
        Long commercialNum = ObjectUtils.equal(tradingChannel.getValue(), PayChannelEnum.WECHAT_PAY.getValue())
                ? properties.getWechatEnterpriseId()
                : properties.getAliEnterpriseId();
        dto.setEnterpriseId(commercialNum);
        dto.setProductAppId("jzo2o.orders");
        dto.setProductOrderNo(orders.getId());
        dto.setTradingChannel(tradingChannel);
        dto.setTradingAmount(orders.getRealPayAmount());
        dto.setMemo(orders.getServeItemName());

        if(ObjectUtils.isNotNull(orders.getTradingChannel())
                && ObjectUtils.notEqual(orders.getTradingChannel(), tradingChannel.getValue())) {
            // 更换支付渠道
            dto.setChangeChannel(true);
        }

        return dto;
    }
}
